package il.technion.cs236369.webserver;

import il.technion.cs236369.webserver.typeHandlers.Session;
import il.technion.cs236369.webserver.typeHandlers.TSPEngine;

import java.io.IOException;
import java.net.Socket;
import java.util.Properties;
import java.util.Queue;

import org.apache.http.Header;
import org.apache.http.HttpException;
import org.apache.http.HttpResponse;
import org.apache.http.impl.DefaultHttpServerConnection;


public class RequestHandler extends Thread{

	//a reference to the requests queue
	Queue<ExtendedHttpRequest> requests = null;
	//each handler receives a serial number (for debug purpose)
	int handlerNumber = 0;

	public RequestHandler(Queue<ExtendedHttpRequest> requestsQueue, int number){
		requests = requestsQueue;
		handlerNumber = number;
	}

	/**
	 * This method continuously listen to the request queue, extract request and handles them
	 */
	public void run()
	{
		ExtendedHttpRequest request = null;
		while (true)
		{
			synchronized (requests)
			{
				while (requests.isEmpty())
				{
					try
					{
						requests.wait();
					} catch (InterruptedException e)
					{
						System.err.println("Thread " + handlerNumber + " was intrupted");
					}
				}
				request = requests.remove();
			}
			handleRequest(request);
		}
	}

	/**
	 * This method receives a request, handles it, and closes it
	 * @param request
	 */
	private void handleRequest(ExtendedHttpRequest request) 
	{
		Socket socket = request.getSocket();
		HttpResponse response = null;

		//check that if convert:xml/json header exist than the type is xml 
		if (checkForConverXMLJSONtHeader(request) && !WebServer.map.getContentType(request).equals("xml"))
		{
			HttpResponser responser = new HttpResponser();
			responser.sendErrorResponse(socket,400,"Bad Request", "Convert xml/json header was in the request");
		}
		else
		{
			TypeHandler handler;

			Integer id = SessionManager.initiateSession(request, response);
			Session session = SessionManager.getSession(id);
			Properties props = new Properties();
			props.setProperty("session", Integer.toString(id));
			boolean sessionWasntEmpty = !session.isEmpty();

			//Check if a specific type handler exist, if not call default type handler
			if (WebServer.map.TypeHandlers.containsKey(Mappings.getExtension(request)))
			{
				handler = new TSPEngine(props);
			} else
			{
				handler = new DefaultlHandler(null);
			}

			response = handler.handle(request);

			if (sessionWasntEmpty && session.isEmpty()) {
				SessionManager.invalidateSession(id);
				String str = "id=0; expires=Thu, 01-Jan-1970 00:00:01 GMT;";
				response.setHeader("Set-Cookie", str);
			} else
			{
				response.setHeader("Set-Cookie", "id=" + Integer.toString(id) + ";");
			}

			DefaultHttpServerConnection conn = request.getServerConn();

			try
			{
				conn.sendResponseHeader(response);
				conn.sendResponseEntity(response);
				conn.close();
			}  catch (IOException e){
				System.err.print("IO Error: ");
				System.err.println(e.getMessage());
				e.printStackTrace(System.err);
			}
			catch (HttpException e){
				System.err.print("HTTP Error: ");
				System.err.println(e.getMessage());
				e.printStackTrace(System.err);
			}
			try{
				socket.close();
			} 
			catch (IOException e) {
				System.err.println("handler unable to close socket");
				e.printStackTrace();
			}
		}
	}
	
	private boolean checkForConverXMLJSONtHeader(ExtendedHttpRequest request)
	{
		for (Header h: request.getHttpRequest().getAllHeaders())
			if (h.getName().contains("Convert") && h.getValue().contains("xml/json"))
				return true;
		return false;
	}
	
}

